package org.study.sync;

import com.alibaba.fastjson2.JSON;
import lombok.*;

import java.util.*;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.TimeUnit;
import java.util.function.Consumer;
import java.util.function.Supplier;
import java.util.stream.Collectors;

/**
 * https://dalin.blog.csdn.net/article/details/104528915、
 * https://blog.51cto.com/u_15049004/2561382
 *
 * @author Administrator
 * @date 2021-08-30
 */
public class CompletableFuture1 {
    public static void main(String[] args) {
        long begin = System.currentTimeMillis();
        //多线程环境需要注意线程安全问题
        List<UserInfo> userInfoList = Collections.synchronizedList(new ArrayList<>());
        for (int i = 0; i <= 20; i++) {
            UserInfo userInfo = new UserInfo();
            userInfo.setId(i);
            userInfo.setName("username" + i);
            userInfo.setCarId(i);
            userInfo.setJobId(i);
            userInfo.setHomeId(i);
            userInfoList.add(userInfo);
        }
        userInfoList.forEach(item -> System.out.println(JSON.toJSONString(item)));
        //stream 查询一个用户花费3s  并行计算后一个用户1秒左右 查询21个用户花费21秒
        //parallelStream 速度更慢
        userInfoList.stream().map(userInfo -> {
            QueryUserService queryUserService = new QueryUserService();
            userInfo = queryUserService.convertUserInfo1(userInfo);
            return userInfo;
        }).collect(Collectors.toList());
        System.out.println("=============");
        long end = System.currentTimeMillis();
        System.out.println(end - begin);
        userInfoList.forEach(item -> System.out.println(JSON.toJSONString(item)));
    }
}

class QueryUserService {
    private Supplier<QueryUtils> queryUtilsSupplier = QueryUtils::new;

    public UserInfo convertUserInfo1(UserInfo userInfo) {
        QuerySupplier querySupplier1 = new QuerySupplier(userInfo.getCarId(), "car", queryUtilsSupplier.get());
        CompletableFuture<String> getCarDesc = CompletableFuture.supplyAsync(querySupplier1);
        getCarDesc.thenAccept(new Consumer<String>() {
            @Override
            public void accept(String carDesc) {
                userInfo.setCarDes(carDesc);
            }
        });
        QuerySupplier querySupplier2 = new QuerySupplier(userInfo.getHomeId(), "home", queryUtilsSupplier.get());
        CompletableFuture<String> getHomeDesc = CompletableFuture.supplyAsync(querySupplier2);
        getHomeDesc.thenAccept(new Consumer<String>() {
            @Override
            public void accept(String homeDesc) {
                userInfo.setHomeDes(homeDesc);
            }
        });
        QuerySupplier querySupplier3 = new QuerySupplier(userInfo.getJobId(), "job", queryUtilsSupplier.get());
        CompletableFuture<String> getJobDesc = CompletableFuture.supplyAsync(querySupplier3);
        getJobDesc.thenAccept(new Consumer<String>() {
            @Override
            public void accept(String jobDesc) {
                userInfo.setJobDes(jobDesc);
            }
        });
        CompletableFuture<Void> getUserInfo = CompletableFuture.allOf(getCarDesc, getHomeDesc, getJobDesc);
        getUserInfo.thenAccept(new Consumer<Void>() {
            @Override
            public void accept(Void result) {
                System.out.println("全部完成查询");
            }
        });
        getUserInfo.join();
        return userInfo;
    }


    public UserInfo convertUserInfo2(UserInfo userInfo) {
        QueryUtils queryUtils = new QueryUtils();
        CompletableFuture<String> getCarDesc = CompletableFuture.supplyAsync(() -> {
            Integer carId = userInfo.getCarId();
            String queryCar = queryUtils.queryCar(carId);
            return queryCar;
        });
        getCarDesc.thenAccept(new Consumer<String>() {
            @Override
            public void accept(String carDesc) {
                userInfo.setCarDes(carDesc);
            }
        });
        CompletableFuture<String> getHomeDesc = CompletableFuture.supplyAsync(() -> {
            Integer homeId = userInfo.getHomeId();
            String queryHome = queryUtils.queryHome(homeId);
            return queryHome;
        });
        getHomeDesc.thenAccept(new Consumer<String>() {
            @Override
            public void accept(String homeDesc) {
                userInfo.setHomeDes(homeDesc);
            }
        });
        CompletableFuture<String> getJobDesc = CompletableFuture.supplyAsync(() -> {
            Integer jobId = userInfo.getJobId();
            String queryJob = queryUtils.queryJob(jobId);
            return queryJob;
        });
        getJobDesc.thenAccept(new Consumer<String>() {
            @Override
            public void accept(String jobDesc) {
                userInfo.setJobDes(jobDesc);
            }
        });
        CompletableFuture<Void> getUserInfo = CompletableFuture.allOf(getCarDesc, getHomeDesc, getJobDesc);
        getUserInfo.thenAccept(new Consumer<Void>() {
            @Override
            public void accept(Void result) {
                System.out.println("全部完成查询");
            }
        });
        getUserInfo.join();
        return userInfo;
    }
}

class QuerySupplier implements Supplier<String> {
    private Integer id;
    private String type;
    private QueryUtils queryUtils;

    public QuerySupplier(Integer id, String type, QueryUtils queryUtils) {
        this.id = id;
        this.type = type;
        this.queryUtils = queryUtils;
    }

    @Override
    public String get() {
        if ("home".equals(type)) {
            return queryUtils.queryHome(id);
        } else if ("job".equals(type)) {
            return queryUtils.queryJob(id);
        } else if ("car".equals(type)) {
            return queryUtils.queryCar(id);
        }
        return null;
    }
}

class QueryUtils {
    public String queryCar(Integer carId) {
        try {
            TimeUnit.SECONDS.sleep(1);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        return "car_desc";
    }

    public String queryJob(Integer jobId) {
        try {
            TimeUnit.SECONDS.sleep(1);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        return "job_desc";
    }

    public String queryHome(Integer homeId) {
        try {
            TimeUnit.SECONDS.sleep(1);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        return "home_desc";
    }
}

@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
class UserInfo {
    private Integer id;
    private String name;
    private Integer jobId;
    private String jobDes;
    private Integer carId;
    private String carDes;
    private Integer homeId;
    private String homeDes;
}